"""Implement Task class.

Each normal task corresponds to a Task object, which contains information about
the task, such as creation time, current status, file descriptors."""

import time
import subprocess

UNRUN   = 0
RUNNING = 1
FINISH  = 2

class Task(object):
    def __init__(self, task_id, args, user="anonymous"):
        self.id = task_id
        self.args = args
        self.user = user
        self.status = UNRUN     # Initial status is UNRUN
        self.process = None
        self.open_stdout = False
        self.open_stderr = False
        self.create_time = time.time()
        self.modify_time = self.create_time

    def to_running(self):
        """Switch status from UNRUN to RUNNING."""
        # TODO: check previous status
        self.process = subprocess.Popen(self.args, stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE, close_fds=True)
        self.modify_time = time.time()
        self.status = RUNNING
        self.open_stdout = True
        self.open_stderr = True

    def to_finish(self):
        """Switch status from RUNNING to FINISH."""
        #TODO: check previous status
        #TODO: check whether stdout and stderr are open
        # TODO: Record the exit status of the process
        self.process.wait()
        self.modify_time = time.time()
        self.status = FINISH

    def show_status(self):
        """Show current status of the Task."""
        pass

    def handle_read_stdout(self):
        """Callback, runner would call this function when there is output."""
        buf = self.process.stdout.read()
        self.modify_time = time.time()
        # Note: demo version, real version should log output
        print "[%d][%d]: %s" % (self.id, self.process.pid, buf)

    def handle_read_stderr(self):
        """Callback, runner would call this function when there is error."""
        buf = self.process.stderr.read()
        self.modify_time = time.time()
        # TODO: Handle the stderr buffer
        pass

    def handle_close_stdout(self):
        """Callback, runner would call this when receive EOF on output."""
        self.process.stdout.close()
        self.modify_time = time.time()
        self.open_stdout = False
        if not self.open_stderr:    # Both stdout and stderr close
            self.to_finish()

    def handle_close_stderr(self):
        """Callback, runner would call this when receive EOF on error."""
        self.process.stderr.close()
        self.modify_time = time.time()
        self.open_stderr = False
        if not self.open_stdout:    # Both stdout and stderr close
            self.to_finish()

    def stdout_readable(self):
        """Return boolean value to indicate whether stdout is ready."""
        return self.open_stdout

    def stderr_readable(self):
        """Return boolean value to indicate whether stderr is ready."""
        return self.open_stderr

    def get_id(self):
        """Return the id of the Task."""
        return self.id

    def get_status(self):
        """Return current status of the Task."""
        return self.status

    def get_stdout_fd(self):
        """Return stdout fd of the Task."""
        return self.process.stdout.fileno()

    def get_stderr_fd(self):
        """Return stderr fd of the Task."""
        return self.process.stderr.fileno()
